import { reactive, watch } from "vue";
import { storeKey } from "./injectKey";
import ModuleCollection from "./module/module-collection";
import { isPromise, forEachValue } from "./utils";

// 从根State，找自己当前的State
function getNestedState ( state, path ) {
  return path.reduce( ( state, key ) => state[ key ], state );
}

function installModule ( store, rootState, path, module ) {
  // 模块命名空间
  const namespaced = store._modules.getNamespaced( path )

  // 因为只有根模块的state才具有响应式的能力，
  // 所以需要将子模块的state挂载到根模块的state
  if ( path.length > 0 ) {
    // 父State
    let parentState = path
      .slice( 0, -1 )
      .reduce( ( state, key ) => state[ key ], rootState );
    // 挂载子state
    parentState[ path[ path.length - 1 ] ] = module.state;
  }

  // 收集Getter
  module.forEachGetter( ( functionName, getter ) => {
    store._wrappedGetters[ `${ namespaced }${ functionName }` ] = () => {
      // 从根State，找自己当前的State
      return getter( getNestedState( store.state, path ) )
    }
  } )

  // 收集Mutation
  // 是否是多模块，但是没启用namespaced,函数名称相同多出现多个
  // mutation   {add:[mutation,mutation]}

  // mutation    {a/b/c:[mutation]}
  module.forEachMutation( ( functionName, mutation ) => {
    const entry = store._mutations[ `${ namespaced }${ functionName }` ] || ( store._mutations[ `${ namespaced }${ functionName }` ] = [] )
    // store.commit('add',payload)
    entry.push( ( payload ) => {
      mutation.call( store, getNestedState( store.state, path ), payload )
    } )
  } )

  // 收集Action
  module.forEachAction( ( functionName, action ) => {
    const entry = store._actions[ `${ namespaced }${ functionName }` ] || ( store._actions[ `${ namespaced }${ functionName }` ] = [] )
    entry.push( ( payload ) => {
      // store.dispatch('LOGIN',payload).then(()=>{})
      let res = action.call( store, store, payload );
      // res 是不是一个promise
      if ( !isPromise( res ) ) {
        return Promise.resolve( res );
      }
      return res;
    } );
  } )

  // 处理子模块
  module.forEachChild( ( key, childModule ) => {
    installModule( store, rootState, path.concat( key ), childModule )
  } )
}

export default class Store {
  // 在修改state前先取消警告，在修改
  _withCommit ( mutation ) {
    this._commiting = true;
    mutation();
    this._commiting = false;
  }

  constructor ( options ) {
    const store = this;
    this.strict = options.strict || false; // 是不是严格模式
    this._commiting = false; // 同步执行标志(mutation里面得写同步代码)

    // 模块数据格式化
    store._modules = new ModuleCollection( options );
    store._wrappedGetters = Object.create( null );
    store._mutations = Object.create( null );
    store._actions = Object.create( null );
    // 安装模块，订阅Getters、_mutations、actions
    const state = store._modules.root.state; // 根状态
    installModule( store, state, [], store._modules.root );
    // 让state具有响应式的能力
    resetStoreState( store, state );

    // 插件收集器
    store._subscribes = [];
    // 执行plugins，传递store实例
    options.plugins && options.plugins.forEach( ( plugin ) => plugin( store ) );
  }

  install ( app, injectKey ) {
    // createApp().use(store,'my')
    // 根组件通过provide注入一个store实例
    // 子组件在useStore inject时，会去向上查找store实例
    app.provide( injectKey || storeKey, this );
    // vue2=Vue.prototype.$store = this
    app.config.globalProperties.$store = this; // 增添全局$store属性
  }

  get state () {
    return this._state.data;
  }


  commit = ( type, payload ) => {
    let mutations = this._mutations[ type ] || []
    this._withCommit( () => {
      mutations.forEach( ( mutation ) => mutation( payload ) )
    } )
    // 执行订阅的插件
    this._subscribes.forEach( ( sub ) => sub( { type, payload }, this.state ) );
  }

  // 箭头函数保证this指向
  // actions 可以结构store实例的commit
  dispatch = ( type, payload ) => {
    let actions = this._actions[ type ] || []
    return Promise.all( actions.map( ( mutation ) => mutation( payload ) ) )
  }

  // 订阅插件
  subscribe ( fn ) {
    this._subscribes.push( fn );
  }

  // 整个替换State
  replaceState ( newState ) {
    // 严格模式下 不能直接修改状态
    this._withCommit( () => {
      this._state.data = newState;
    } );
  }
  // 动态注册模块
  registerModule ( path, rawModule ) {
    const store = this;
    if ( typeof path == "string" ) {
      path = [ path ];
    }
    // 格式化新模块
    store._modules.register( rawModule, path )
    // 重新收集安装模块
    installModule( store, store.state, [], store._modules.root );
    // 重新初始化
    resetStoreState( store, store.state );
  }

}

function resetStoreState ( store, state ) {
  store._state = reactive( { data: state } )
  const wrappedGetters = store._wrappedGetters;
  store.getters = {};
  forEachValue( wrappedGetters, ( key, getter ) => {
    // 代理store.getters.xx
    Object.defineProperty( store.getters, key, {
      get: getter,
      enumerable: true,
    } );
  } );
  // 开启严格模式
  // 模式下只能通过commit修改状态，否则警告
  if ( store.strict ) {
    enableStrictMode( store )
  }
}

function enableStrictMode ( store ) {
  watch(
    () => store._state.data,
    () => {
      console.assert(
        store._commiting,
        "do not mutate vuex store state outside mutation handlers"
      );
    },
    { deep: true, flush: "sync" }
  ); // 默认watchApi是异步的，这里改成同步的监控
}



// 格式化用户的参数，实现根据自己的需要，后续使用时方便
// root = {
//     _raw:rootModule,
//     state:rootModule.state, // 用户管理
//     _children:{
//         aCount:{
//             _raw:aModule,
//             state:aModule.state,
//             _children:{
//                 cCount:{
//                     _raw:useCssModule,
//                     state:cModule.state,
//                     _children:{}
//                 }
//             }
//         },
//         bCount:{
//             _raw:bModule,
//             state:bModule.state,
//             _children:{}
//         }
//     }
// }
